package i18nh

import (
	"fmt"
	"github.com/BurntSushi/toml"
	"github.com/nicksnyder/go-i18n/v2/i18n"
	"golang.org/x/text/language"
	"log"
	_const "longmen/server/pkg/common/helper/const"
	"math"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"sync"
)

type (
	TranslateFunc = func(msgId string, a ...interface{}) string
)

var onceLangInstance sync.Once
var object *LangInstance
var LangPack = []string{_const.LangChinese, _const.LangEnglish, _const.LangId}

type LangInstance struct {
	localizes map[language.Tag]*i18n.Localizer
	functions map[language.Tag]TranslateFunc
	lange     string
}

func New(lange string) *LangInstance {
	onceLangInstance.Do(func() {
		object = &LangInstance{
			localizes: make(map[language.Tag]*i18n.Localizer),
			functions: make(map[language.Tag]TranslateFunc),
			lange:     lange,
		}
		err := object.load(LangPack)
		if err != nil {
			log.Fatal(err)
		}
	})
	return object
}

// Load 载入指定语言的翻译文件
func (obj *LangInstance) load(langs []string) error {
	for _, lang := range langs {
		tag, err := language.All.Parse(lang)
		if err != nil {
			return fmt.Errorf("[local18n] Load language bundle '%s' failed, %s", lang, err)
		}

		b := i18n.NewBundle(tag)

		b.RegisterUnmarshalFunc("toml", toml.Unmarshal)
		file, err := func() (string, error) {
			_, filename, _, ok := runtime.Caller(0)
			if !ok {
				return "", fmt.Errorf("[local18n] get lang path failed ")
			}
			prjRootdir := filepath.Dir(filename)
			for i := 0; i < math.MaxInt8; i++ {
				if _, err := os.Stat(filepath.Join(prjRootdir, "go.mod")); err == nil {
					return fmt.Sprintf("%s/lang/%s.toml", prjRootdir, lang), nil
				}
				if prjRootdir == string(os.PathSeparator) {
					break
				}
				prjRootdir = filepath.Dir(prjRootdir)
			}
			return "", fmt.Errorf("[local18n] get lang path error, can not find go.mod file ")
		}()
		if err != nil {
			log.Println(err, "use fixed path")
			file = fmt.Sprintf("../../../lang/%s.toml", lang)
		}
		_, err = b.LoadMessageFile(file)
		if err != nil {
			return fmt.Errorf("[local18n] Load language bundle '%s' failed, %s", lang, err)
		}
		obj.localizes[tag] = i18n.NewLocalizer(b, tag.String())
	}
	return nil
}

// T 返回指定语言的翻译结果
func (obj *LangInstance) T(msgId string, a ...interface{}) string {
	return obj.lang(obj.GetLang())(msgId, a...)
}

func T(msgId string, a ...interface{}) string {
	return object.lang(object.GetLang())(msgId, a...)
}
func (obj LangInstance) GetLang() string {
	return obj.lange
}

// lang 返回指定语言的翻译函数
func (obj *LangInstance) lang(lang string) TranslateFunc {
	tag, err := language.All.Parse(lang)
	if err != nil {
		return obj.defaultTranslate
	}
	local, ok := obj.localizes[tag]
	if !ok {
		return obj.defaultTranslate
	}
	f, ok := obj.functions[tag]
	if !ok {
		f = obj.createTranslateFunc(local)
		obj.functions[tag] = f
	}
	return f
}

// // local
func (obj *LangInstance) createTranslateFunc(l *i18n.Localizer) TranslateFunc {
	return func(msgId string, a ...interface{}) string {
		t := map[string]interface{}{}
		for i := range a {
			t["v"+strconv.Itoa(i+1)] = a[i]
		}
		r, err := l.Localize(&i18n.LocalizeConfig{MessageID: msgId, TemplateData: t})
		if err == nil {
			return r
		}
		return obj.defaultTranslate(msgId, a...)
	}
}

func (obj *LangInstance) defaultTranslate(msg string, a ...interface{}) string {
	return fmt.Sprintf("#local18n miss# %s", msg)
}
